#include "helper.h"
#include "monitor.h"
#include "r-type.h"

extern char assembly[80];
uint32_t SignalException(uint32_t);

/* invalid opcode */
make_helper(inv) {

	uint32_t temp;
	temp = instr_fetch(pc, 4);

	uint8_t *p = (void *)&temp;
	GUI_printf(RED_TEXT, "invalid opcode(pc = 0x%08x): %02x %02x %02x %02x ...\n\n", 
			pc, p[3], p[2], p[1], p[0]);

	GUI_printf(RED_TEXT, "There are two cases which will trigger this unexpected exception:\n\
1. The instruction at pc = 0x%08x is not implemented.\n\
2. Something is implemented incorrectly.\n", pc);
	GUI_printf(RED_TEXT, "Find this pc value(0x%08x) in the disassembling result to distinguish which case it is.\n\n", pc);
	CP0_CHANGE(Cause, ExcCode, 0x0a);
	SignalException(0);
	// del_Screen();
	// assert(0);
}

/* stop temu */
make_helper(temu_trap) {

	GUI_printf(GREEN_TEXT, "temu: HIT GOOD TRAP at $pc = 0x%08x\n\n", cpu.pc);

	temu_state = END;

}

make_helper(temu_bad_trap) {

	GUI_printf(RED_TEXT, "temu: HIT BAD TRAP at $pc = 0x%08x\n\n", cpu.pc);

	temu_state = END;
	
}

uint32_t __SE(uint32_t ErrCode) {

	switch((cp0.Cause & Cause_ExcCode_MASK) >> Cause_ExcCode_SIZE){
		case 0x00:{
			// BREAK EXCEPTION
			// CP0_CHANGE(Cause, IP, )
			break;
		}
		case 0x04:{
			// load or read memory
			GUI_printf(RED_TEXT, "Error Address: 0x%08x", ErrCode);
			cp0.BadVAddr = ErrCode;
			break;
		}
		case 0x05:{
			// write memory
			GUI_printf(RED_TEXT, "Error Address: 0x%08x", ErrCode);
			cp0.BadVAddr = ErrCode;
			break;
		}
		case 0x0c:{
			// Overflow
			GUI_printf(BLUE_TEXT, "Overflow at $pc: 0x%08x", cpu.pc);
			break;
		}
		case 0x08:{
			// SYSCALL
			break;
		}
		case 0x09:{
			// BREAK
			break;
		}
		case 0x0a:{
			// 保留指令
			break;
		}
		// default:
	}
	return 0;
}

uint32_t SignalException(uint32_t ErrCode) {

	if((cp0.Status & Status_EXL_MASK) == 0){
			// 更新CP0.EPC
			cp0.EPC = cpu.pc;

			// 更新CP0.Cause的BD位
			CP0_CHANGE(Cause, BD, 0);
			// 更新CP0.Status的EXL位
			CP0_CHANGE(Status, EXL, 1);
			__SE(cpu.pc);
			// 执行异常处理程序
			// 交给测试人员编写

			// ......
			
			// eret(cpu.pc);	
		}
	return 0;
}

